#ifndef _FILE_IO_H_
#define _FILE_IO_H_
#include "../sleipner_config.h"
#include <string>
#include <vector>
#ifdef _PLATFORM_WII
	#include <revolution.h>
	#include <revolution/nand.h>
	#include <revolution/dvd.h>
	#include <revolution/types.h>
#endif

#if defined(_PLATFORM_ANDROID) && defined(_SDL2)
#include "SDL2/include/SDL.h"
#endif

namespace util
{
class	AbstractFile
{
public:
	enum			FILE_OPTIONS
	{
		FILE_READ		=	0x01 << 0,
		FILE_WRITE		=	0x01 << 1,
		FILE_BINARY		=	0x01 << 2,
		FILE_ASCII		=	0x01 << 3,
		FILE_MEMORY		=	0x01 << 4,	// this is a memory file
		// wii specific options; it has different IO routines for disk or NAND RAM (savegame)
		// by default, it assumes that any file that has write access is for NAND
		FILE_DISC		=	0x01 << 5,
		FILE_NAND		=	0x01 << 6,
		FILE_MEM32		= 	0x01 << 7	// memory is already 32b aligned. No need for temp buffers
	};
					AbstractFile() : m_Format(0), m_Open(false) {};
	virtual			~AbstractFile() {};
	virtual			bool			Open(const std::string& Name, unsigned long	Format)
	{
		m_Name = Name;
		m_Format = Format;
		return true;
	}

	virtual			void			Close()= 0;
	virtual			unsigned int	GetSize()= 0;
	virtual			bool			Write(void*	pData, unsigned int		Size)= 0;
	virtual			bool			WriteStr(const std::string& Data)= 0;
	virtual			bool			Read(void* pData, unsigned int		Size)= 0;

	// seek set
	virtual			void			SetPos(unsigned int Pos)= 0;
	bool			IsOpen() const { return m_Open; };

protected:
	std::string		m_Name;
	unsigned long	m_Format;
	bool			m_Open;

};


class	FileIO : public AbstractFile
{
public:

	FileIO();
	virtual			~FileIO();
	virtual			bool			Open(const std::string& Name, unsigned long	Format);
	virtual			void			Close();
	virtual			unsigned int	GetSize();
	virtual			bool			Write(void*	pData, unsigned int		Size);
	virtual			bool			WriteStr(const std::string& Data);
	virtual			bool			Read(void* pData, unsigned int		Size);

	// seek set
	virtual			void			SetPos(unsigned int Pos);


	
/// generic functions that fit under file-systems, and require custom implementations
	static bool			MakeDirectory(const std::string& Name);
	static void			ReadDirectory(const std::string& Path, std::vector<std::string>& Files);
	static bool			CheckFreeSpace(int Size);
	static bool			FileExists(const std::string& Name);
	
#ifdef _PLATFORM_WII
	unsigned char*		GetTempBuffer(unsigned int Size, void* pToWrite = NULL);
	void				FreeTempBuffer(unsigned char* pData);
	bool				MoveToHome(const std::string& From);
#endif // 
protected:
#ifdef _PLATFORM_WII
	DVDFileInfo		m_DVDFile;
	NANDFileInfo	m_NANDFile;
	static const int 	MAX_TEMP_SIZE = 4096;
	unsigned char*	m_pStaticBuffer;
#else	
	FILE*			m_pFile;
#endif

#ifdef _PLATFORM_ANDROID
	SDL_RWops*		m_pSDLFile;
#endif
};

class	MemoryFile : public AbstractFile
{
public:
					MemoryFile();
	virtual			~MemoryFile();
	virtual			bool			Open(const std::string& Name, unsigned long	Format);
	virtual			void			Close();
	virtual			bool			Write(void*	pData, unsigned int		Size);
	virtual			bool			WriteStr(const std::string& Data);
	virtual			bool			Read(void* pData, unsigned int		Size);
	virtual			void			SetPos(unsigned int Pos);

	unsigned char*					GetData() { return m_DataA; };
	virtual			unsigned int	GetSize() { return m_Current; };

	// some utilities	
	bool							PackData(unsigned int& NewSize, unsigned char* &DataA, unsigned int& Checksum);
	static unsigned int				BuildChecksum(unsigned char* DataA, unsigned int Size);
protected:
	void							Grow(unsigned int ToNew);
	unsigned int		m_Current, m_Max;
	unsigned char*		m_DataA;
};

} //namespace util

#endif // _FILE_IO_H_
